package com.aizuda.boot.modules.business.contractNumber;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.aizuda.boot.modules.business.contract.entity.*;
import com.aizuda.boot.modules.business.contract.mapper.ContractFieldValueMapper;
import com.aizuda.boot.modules.business.contract.mapper.ContractMapper;
import com.aizuda.boot.modules.business.contract.service.ContractFieldService;
import com.aizuda.boot.modules.business.contract.service.ContractWorkflowService;
import com.aizuda.boot.modules.business.contract.service.ContractWorkflowTypeService;
import com.aizuda.boot.modules.business.contract.util.AuthUtil;
import com.aizuda.boot.modules.business.contractNumber.domain.ContractNumberEvent;
import com.aizuda.boot.modules.business.contractNumber.domain.entity.ContractNumberRuleEntity;
import com.aizuda.boot.modules.business.contractNumber.domain.resquest.GenerateNumberDTO;
import com.aizuda.boot.modules.business.contractNumber.service.ContractNumberRuleService;
import com.aizuda.boot.modules.common.constant.enums.RuleTypeEnums;
import com.aizuda.boot.modules.common.constant.enums.SystemFieldsEnum;
import com.aizuda.boot.modules.common.util.DocxTextInserterUtil;
import com.aizuda.boot.modules.common.util.PdfTextInserterUtil;
import com.aizuda.boot.modules.file.domain.entity.FileInfo;
import com.aizuda.boot.modules.file.enums.FileFolderTypeEnum;
import com.aizuda.boot.modules.file.service.FileInfoService;
import com.aizuda.core.api.ApiAssert;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author sangyirong
 * @ClassName ContractNumberListener
 * @Version 1.0
 * @Date 2025/7/19 18:12
 */
@Slf4j
@Component
public class ContractNumberListener {

    @Value("${file.storage.local.upload-path:#{null}}")
    private String uploadPath;


    @Resource
    private ContractMapper contractMapper;

    @Resource
    private ContractFieldValueMapper contractFieldValueMapper;

    @Resource
    private ContractWorkflowTypeService contractWorkflowTypeService;

    @Resource
    private ContractWorkflowService contractWorkflowService;

    @Resource
    private ContractNumberRuleService contractNumberRuleService;

    @Resource
    private ContractFieldService contractFieldService;

    @Resource
    private FileInfoService fileInfoService;

    @EventListener
    public void onContractNumberEvent(ContractNumberEvent event) {
        log.info("进入到合同编号生成监听器，event：{}", JSONUtil.toJsonStr(event));
        Integer contractId = event.getContractId();

        ContractEntity contractEntity = contractMapper.selectById(contractId);

        if (ObjUtil.isNull(contractEntity)) {
            log.warn("合同不存在，合同ID：{}", contractId);
            return;
        }

        log.debug("查询到的合同信息：{}", JSONUtil.toJsonStr(contractEntity));

        log.info("开始为编号{}的合同生成合同编号", contractId);

        // 直接通过fieldCode查询合同编号字段值
        ContractFieldValueEntity entity = contractFieldValueMapper.selectOne(Wrappers.<ContractFieldValueEntity>lambdaQuery()
                .eq(ContractFieldValueEntity::getContractId, contractId)
                .eq(ContractFieldValueEntity::getFieldCode, SystemFieldsEnum.CONTRACT_NUMBER.getCode()));

        // 判断是否已经生成过编号
        if (entity != null && StrUtil.isNotBlank(entity.getFieldValue())) {
            log.info("合同{}已存在编号：{}，跳过生成", contractId, entity.getFieldValue());
            return;
        }

        // 直接通过fieldCode查询需要的字段值
        GenerateNumberDTO dto = new GenerateNumberDTO();
        Map<String, String> fieldMap = contractFieldValueMapper.selectList(Wrappers.<ContractFieldValueEntity>lambdaQuery()
                        .eq(ContractFieldValueEntity::getContractId, contractId)
                        .in(ContractFieldValueEntity::getFieldCode, SystemFieldsEnum.PAYMENT_TYPE.getCode(), SystemFieldsEnum.CONTRACT_TYPE.getCode(), SystemFieldsEnum.OUR.getCode()))
                .stream().collect(Collectors.toMap(ContractFieldValueEntity::getFieldCode, ContractFieldValueEntity::getFieldValue));

        // 无论是否有支付类型匹配一个收支类型
        dto.setDocumentType(getDocument(fieldMap.getOrDefault(SystemFieldsEnum.PAYMENT_TYPE.getCode(), "")));
        if (fieldMap.containsKey(SystemFieldsEnum.OUR.getCode())) {
            String own = fieldMap.get(SystemFieldsEnum.OUR.getCode());
            List<Integer> ownIds = JSON.parseArray(own, Integer.class);
            dto.setLegalId(ownIds.get(0));
        }
        if (fieldMap.containsKey(SystemFieldsEnum.CONTRACT_TYPE.getCode())) {
            dto.setContractTypeId(Integer.parseInt(fieldMap.get(SystemFieldsEnum.CONTRACT_TYPE.getCode())));

            int typeId = Integer.parseInt(fieldMap.get(SystemFieldsEnum.CONTRACT_TYPE.getCode()));
            log.info("合同类型ID: {}", typeId);

            // 1. 根据合同类型查找工作流ID列表
            List<ContractWorkflowTypeEntity> workflowTypeList = contractWorkflowTypeService.list(
                    new LambdaQueryWrapper<ContractWorkflowTypeEntity>()
                            .eq(ContractWorkflowTypeEntity::getContractTypeId, typeId)
            );

            if (workflowTypeList.isEmpty()) {
                log.warn("未找到合同类型对应的工作流，合同类型ID: {}", typeId);
                return;
            }

            Set<Long> typeWorkflowIds = workflowTypeList.stream()
                    .map(ContractWorkflowTypeEntity::getWorkflowId)
                    .collect(Collectors.toSet());

            log.info("找到 {} 个匹配的工作流ID: {}", typeWorkflowIds.size(), typeWorkflowIds);

            // 2. 在匹配的工作流中查找优先级最高的已启用工作流
            ContractWorkflowEntity optimalWorkflow = contractWorkflowService.getOne(
                    new LambdaQueryWrapper<ContractWorkflowEntity>()
                            .in(ContractWorkflowEntity::getId, typeWorkflowIds)
                            .eq(ContractWorkflowEntity::getIsEnabled, true)
                            .orderByDesc(ContractWorkflowEntity::getPriority)
                            .last("LIMIT 1")
            );

            if (optimalWorkflow == null) {
                log.warn("未找到已启用的工作流，工作流ID集合: {}", typeWorkflowIds);
                return;
            }

            dto.setRuleType(getRuleType(optimalWorkflow.getWorkflowType()));
        }
        ContractNumberRuleEntity rule = contractNumberRuleService.getOne(Wrappers.<ContractNumberRuleEntity>lambdaQuery()
                .eq(ContractNumberRuleEntity::getRuleType, dto.getRuleType())
                .last("limit 1"));
        ApiAssert.fail(Objects.isNull(rule), "合同编号规则不存在");
        ApiAssert.fail(!rule.getIsEnabled(), "合同编号规则已禁用");
        if (!rule.getGenerateTiming().equals(event.getGenerateTiming())) {
            log.warn("合同编号规则生成时机不匹配，当前时机：{}，规则时机：{}", event.getGenerateTiming(), rule.getGenerateTiming());
            return;
        }

        String contractNumber = contractNumberRuleService.getContractNumber(dto);
        if (StrUtil.isBlank(contractNumber)) {
            log.error("生成合同编号失败，合同ID：{}，规则：{}", contractId, JSONUtil.toJsonStr(rule));
            return;
        }

        if (ObjUtil.isNull(entity))
            entity = new ContractFieldValueEntity();

        entity.setContractId(contractId);
        entity.setFieldCode(SystemFieldsEnum.CONTRACT_NUMBER.getCode());
        entity.setFieldId(contractFieldService.getOne(Wrappers.<ContractFieldEntity>lambdaQuery()
                .eq(ContractFieldEntity::getCode, SystemFieldsEnum.CONTRACT_NUMBER.getCode())
                .last("limit 1")).getId());
        entity.setFieldValue(contractNumber);
        contractFieldValueMapper.insertOrUpdate(entity);
        log.info("生成合同编号成功，合同编号：{}", contractNumber);

        // 在合同文件中添加合同编号
        String fileId = contractFieldValueMapper.getFieldValueByCode(contractId, SystemFieldsEnum.MAIN_CONTRACT_FILE.getCode());
        if (StrUtil.isBlank(fileId)) {
            log.warn("未找到合同文件，合同ID：{}", contractId);
            return;
        }
        FileInfo fileInfo = fileInfoService.getById(fileId);
        if (ObjUtil.isNull(fileInfo)) {
            log.info("未找到文件信息，文件ID：{}", fileId);
            return;
        }
        String inputPath = uploadPath + fileInfo.getFileKey();

        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
        String time = LocalDateTimeUtil.format(LocalDateTime.now(), DatePattern.PURE_DATETIME_PATTERN);
        String newFileName = uuid + "_" + time;

        if (StrUtil.isNotEmpty(fileInfo.getFileType())) {
            newFileName = newFileName + "." + fileInfo.getFileType();
        }
        String fileKey = Objects.requireNonNull(FileFolderTypeEnum.getByValue(fileInfo.getFolderType())).getFolder() + newFileName;

        String outputPath = uploadPath + fileKey;

        try {
            log.info("开始添加合同编号，源文件路径：{}，目标文件路径：{}", inputPath, outputPath);
            if (fileInfo.getFileType().equals("pdf")) {
                log.info("PDF文件，开始添加合同编号");
                float fontSize = 12;
                float pageHeight = PdfTextInserterUtil.getFirstPageHeight(inputPath);

                float x = 10; // 左边距
                float y = pageHeight - fontSize - 10; // 顶部偏移 10pt
                PdfTextInserterUtil.insertText(inputPath, outputPath, contractNumber, 0, x, y, fontSize);
                log.info("PDF文件添加合同编号成功");
            } else if (fileInfo.getFileType().equals("docx")) {
                log.info("DOCX文件，开始添加合同编号");
                DocxTextInserterUtil.insertFloatingTextbox(inputPath, outputPath, contractNumber,
                        new DocxTextInserterUtil.TextBoxPosition(0, 0, 200, 30));
                log.info("DOCX文件添加合同编号成功");
            } else {
                log.warn("不支持的文件类型：{}，仅支持PDF和DOCX", fileInfo.getFileType());
                return;
            }
            FileInfo newFileInfo = new FileInfo();
            BeanUtils.copyProperties(fileInfo, newFileInfo);
            newFileInfo.setFileId(null);
            newFileInfo.setCreatorId(AuthUtil.getCurrentUser().getId());
            newFileInfo.setCreateTime(new Date());
            newFileInfo.setUpdateTime(new Date());
            newFileInfo.setFileKey(fileKey);
            fileInfoService.save(newFileInfo);

            contractFieldValueMapper.update(Wrappers.<ContractFieldValueEntity>lambdaUpdate()
                    .eq(ContractFieldValueEntity::getContractId, contractId)
                    .eq(ContractFieldValueEntity::getFieldCode, SystemFieldsEnum.MAIN_CONTRACT_FILE.getCode())
                    .set(ContractFieldValueEntity::getFieldValue, newFileInfo.getFileId()));
        } catch (Exception e) {
            log.error("为合同文件添加添加合同编号失败", e);
        }
    }


    private RuleTypeEnums getRuleType(String workflowType) {
        return RuleTypeEnums.valueOf(switch (workflowType) {
            case "CHANGE", "UPDATE_FORM" -> "CONTRACT_CHANGE";
            case "TERMINATION", "INVALID" -> "CONTRACT_TERMINATE";
            default -> "CONTRACT_APPLY";
        });
    }


    public String getDocument(String type) {
        return switch (type) {
            case "支出类" -> "EXP";
            case "收入类" -> "INC";
            case "无收无支" -> "BAL";
            case "成本类" -> "MIX";
            default -> "OTH";
        };
    }
}
